在React Hooks中使用生命周期方法

本文来自于Sollrei

前言

因为项目上用到了hooks+ts,在使用定时任务的时候,退出当前组件时,仍然会执行定时任务,但是在hooks中没有componentWillUnMount方法,所以就网上查找资料。

React新版本的生命周期

react 16.3之后新增了两个生命周期getDerivedStateFromProps和getSnapshotBeforeUpdate,并且原来的componentWillMount,componentWillReceiveProps以及componentWillUpdate将被移除。

constructor

函数组件不用写constructor,用useState初始化state

getDerivedStateFromProps

这个方法基本用来替代componentWillReceiveProps,它是个静态方法,也就是说不能访问this,也就是说不能改this.state

官方栗子

1
2
3
4
5
6
7
8
9
10
11
12
function ScrollView({row}) {
let [isScrollingDown, setIsScrollingDown] = useState(false);
let [prevRow, setPrevRow] = useState(null);

if (row !== prevRow) {
// 上次渲染后row发生变化 更新isScrollingDown.
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}

return `Scrolling down: ${isScrollingDown}`;
}

shouldComponentUpdate

使用React.memo,类似PureComponent,但它只对比props的变化

1
2
3
const Demo = React.memo((props) => {
// ...
})

对子组件可以使用useMemo

1
2
3
4
5
6
7
8
9
10
11
12
function Parent({ a, b }) {
// 只在a变化时re-render
const child1 = useMemo(() => <Child1 a={a} />, [a]);
// 只在b变化时re-render
const child2 = useMemo(() => <Child2 b={b} />, [b]);
return (
<>
{child1}
{child2}
</>
)
}

render

那就是函数它自个儿了……
下面几个可以使用useEffect(fn, […watchStates])实现的

componentDidMount

第二个参数传空数组

这么写在useEffect里使用一些state的时候会报错”missing dependency”,暂时用了eslint-disable-line

1
2
3
4
5
6
7
8
9
10
11
12
13
function Demo () {
const [title, setTitle] = useState('hello');

useEffect(() => {
document.title = title;
// do ...
}, []); // eslint-disable-line

// 点击文字是 hello world world .... 但是页面title是hello
return (
<div onClick={() => setTitle(title + ' world')}>{title}</div>
);
}

componentDidUpdate

只传一个参数,每次render就都会调用这个函数,和componentDidUpdate不同的是第一次render也会执行它

1
2
3
4
5
6
7
8
9
10
11
12
function Demo () {
const [title, setTitle] = useState('hello');

useEffect(() => {
document.title = title;
// do ...
});

return (
<div onClick={() => setTitle(title + ' world')}>{title}</div>
);
}

如果不希望在第一次(初始)render时候调用,可以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Demo () {
const [title, setTitle] = useState('hello');
const first = useRef(true);

useLayoutEffect(() => {
if (first.current) {
first.current = false;
return;
}

document.title = title;
console.log("componentDidUpdateFunction");
});

return (
<div onClick={() => setTitle(title + ' world')}>{title}</div>
);
}

componentWillUnmount

在useEffect的第一个函数参数中返回一个函数,这个函数就会在unmount时候被调用

1
2
3
4
5
6
7
8
9
10
11
12
13
function Demo () {
const [title, setTitle] = useState('hello');

useEffect(() => {
return () => {
console.log('componentWillUnmount')
}
});

return (
<div onClick={() => setTitle(title + ' world')}>{title}</div>
);
}

最后最后componentDidCatch和getDerivedStateFromError暂时还不能用Hook来实现,暂时。